#include "rs485msgque.h"
#include <string.h>

typedef struct
{
    unsigned char msg_queue[MAX_MSG_LEN];
    int front;
    int rear;
} MSGQUEUE;

static MSGQUEUE RS485_msg[2];

void InitRs485Msg()
{
    memset(&(RS485_msg[0]), 0, sizeof(MSGQUEUE));
    memset(&(RS485_msg[1]), 0, sizeof(MSGQUEUE));
    RS485_msg[0].front = -1;
    RS485_msg[1].front = -1;
    RS485_msg[0].rear = -1;
    RS485_msg[1].rear = -1;
}

int RsMsgQueIsFull(int chn)
{
    if (chn < 0 || chn > 1)
    {
        return -1;
    }
    MSGQUEUE* msg_chn = &(RS485_msg[chn]);

    if (chn < 0 || chn > 1)
    {
        return 0;
    }
    if ((msg_chn->rear + 1) % MAX_MSG_LEN == msg_chn->front)
        return 1;
    return 0;
}

int RsMsgQueReset(int chn)
{
    if (chn < 0 || chn > 1)
    {
        return -1;
    }
    MSGQUEUE* msg_chn = &(RS485_msg[chn]);

    msg_chn->rear = -1;
    msg_chn->front = -1;
    memset(msg_chn->msg_queue, 0, MAX_MSG_LEN * sizeof(unsigned char));
    return 0;
}

int RsMsgQueIsEmpty(int chn)
{
    if (chn < 0 || chn > 1)
    {
        return -1;
    }
    MSGQUEUE* msg_chn = &(RS485_msg[chn]);

    if (msg_chn->front == -1)
        return 1;
    return 0;
}

short RsMsgEnqueue(int chn, unsigned char msg)
{
    if (chn < 0 || chn > 1)
    {
        return -1;
    }
    MSGQUEUE* msg_chn = &(RS485_msg[chn]);

    if (RsMsgQueIsFull(chn))
    {
        // 满栈后直接替换
        unsigned char a;
        RsMsgDequeue(chn, &a);
    }

    if (msg_chn->front == -1)
        msg_chn->front = 0;
    msg_chn->rear = (msg_chn->rear + 1) % MAX_MSG_LEN;
    msg_chn->msg_queue[msg_chn->rear] = msg;
    return 0;
}

short RsMsgDequeue(int chn, unsigned char* msg)
{
    if (chn < 0 || chn > 1)
    {
        return -1;
    }
    MSGQUEUE* msg_chn = &(RS485_msg[chn]);

    if (msg == NULL)
        return -1;
    if (RsMsgQueIsEmpty(chn))
    {
        return -1;
    }
    else
    {
        *msg = msg_chn->msg_queue[msg_chn->front];
        if (msg_chn->front == msg_chn->rear)
        {
            msg_chn->front = -1;
            msg_chn->rear = -1;
        }
        else
        {
            msg_chn->front = (msg_chn->front + 1) % MAX_MSG_LEN;
        }
        return 0;
    }
}

unsigned int RsMsgEnqueueAlot(int chn, unsigned char* msg, int len)
{
    if (chn < 0 || chn > 1)
    {
        return -1;
    }
    MSGQUEUE* msg_chn = &(RS485_msg[chn]);

    int i = 0;
    // @FIXME liwang 效率太低
    while (i < len)
    {
        if (RsMsgQueIsFull(chn))
        {
            unsigned char temp;
            RsMsgDequeue(chn, &temp);
        }
        RsMsgEnqueue(chn, msg[i]);
        i++;
    }
    return RsMsgQueSize(chn);
}

unsigned int RsMsgDequeueAlot(int chn, unsigned char* msg, int len)
{
    if (chn < 0 || chn > 1)
    {
        return -1;
    }
    MSGQUEUE* msg_chn = &(RS485_msg[chn]);

    if (RsMsgQueIsEmpty(chn))
    {
        return -1;
    }
    if (len > RsMsgQueSize(chn))
    {
        len = RsMsgQueSize(chn);
    }
    int i = 0;
    while (msg_chn->front != msg_chn->rear && i < len)
    {
        msg[i] = msg_chn->msg_queue[msg_chn->front];
        msg_chn->front = (msg_chn->front + 1) % MAX_MSG_LEN;
        ++i;
    }
    if (msg_chn->front == msg_chn->rear)
    {
        msg_chn->front = -1;
        msg_chn->rear = -1;
    }
    return len;
}

unsigned int RsMsgQueGetAll(int chn, unsigned char* msg)
{
    if (chn < 0 || chn > 1)
    {
        return -1;
    }
    MSGQUEUE* msg_chn = &(RS485_msg[chn]);

    if (RsMsgQueIsEmpty(chn))
    {
        return -1;
    }
    int len = RsMsgQueSize(chn);
    int i = 0;
    while (msg_chn->front != msg_chn->rear)
    {
        msg[i] = msg_chn->msg_queue[msg_chn->front];
        msg_chn->front = (msg_chn->front + 1) % MAX_MSG_LEN;
        ++i;
    }
    msg_chn->front = -1;
    msg_chn->rear = -1;
    return len;
}

int RsMsgQueSize(int chn)
{
    if (chn < 0 || chn > 1)
    {
        return -1;
    }
    MSGQUEUE* msg_chn = &(RS485_msg[chn]);

    if (msg_chn->front == -1)
    {
        return 0;
    }
    int size = ((msg_chn->rear + MAX_MSG_LEN - msg_chn->front) % MAX_MSG_LEN);
    return size + 1;
}
